/* NovoDev_CH347.cpp */


#include "pch.h"
#include "NovoDev_CH347.h"

#pragma comment(lib, "libs/CH347DLL.LIB")

#define WRITE_WORD   0 
#define DUMMY_WORD   0xFFFFFFFF
#define READ_WORD    1
#define BURST_WRITE_LENGTH   1024*10
#define BURST_READ_LENGTH    1024*4

/// <summary>
/// Little Endian to Big Endian
/// </summary>
/// <param name="data"></param>
/// <param name="width">Only support 2/4</param>
void LE2BE(UCHAR* data, int width)
{
    char tempData = 0;
    int cnt = width / 2;
    for (int ix = 0; ix < cnt; ix++)
    {
        tempData = data[ix];
        data[ix] = data[width - ix - 1];
        data[width - ix - 1] = tempData;
    }
}

int NovoDev_CH347::Novo_InitDev(PDEV_CONFIG config)
{
    dev_config = config;
	return 0;
}

int NovoDev_CH347::Novo_EnumDevice()
{
    int ix = 0;
    HANDLE tempHDev = NULL;
    for ( ix = 0; ix < 10; ix++)
    {
        tempHDev = CH347OpenDevice(ix);
        if ((unsigned int)tempHDev == 0xffffffff)
            return ix;
        else
        {
            if (CH347CloseDevice(ix))
                tempHDev = NULL;
            else
                return ERR_Failed;
        }
    }

	return ix;
}

int NovoDev_CH347::Novo_SetDeviceId(int DevID)
{
	int ret = 0;
	mDevID = DevID;
	return ret;
}

int NovoDev_CH347::Novo_OpenDevice()
{
    int ret = 0;
    hDev = CH347OpenDevice(mDevID);
    if ((unsigned int)hDev != 0xffffffff)
    {
        ifDevOpen = true;
        ret = SUCCESS;
    }
    else
        ret = ERR_NO_DEVICE;

    return ret;
}

int NovoDev_CH347::Novo_CloseDevice()
{
    bool ret = 0;
    ret = CH347CloseDevice(mDevID);
    ifDevOpen = false;
    return (ret ? SUCCESS : ERR_Failed);
}

int NovoDev_CH347::Novo_GetDevInfo(void* pDevInfo)
{
    mDeviceInforS devInfo = {0};
    bool ret = CH347GetDeviceInfor(mDevID, (mPDeviceInforS)&devInfo);
	//int ret = ERR_NOT_SUPPORT;
	return (ret ? SUCCESS : ERR_Failed);
}

void NovoDev_CH347::Novo_GetDevName(char* pDevName)
{
	memcpy(pDevName, (char*)DEV_NAME, sizeof(DEV_NAME));
	pDevName = (char*)DEV_NAME;
	return;
}

///IIC
int NovoDev_CH347::Novo_IIC_Init(PIIC_CONFIG config)
{
    int ret = 0;

    ULONG iMode = (ULONG)config->ClockSpeedHz;
    if (iMode > 6)
        iMode = 6;  // Clipping max setting

    ret = CH347I2C_Set(mDevID, ULONG(iMode)) ? SUCCESS : ERR_Failed;

    return ret;
}

int NovoDev_CH347::Novo_IIC_SetIndex(int IICIndex)
{
	int ret = ERR_NOT_SUPPORT;

	return ret;
}

int NovoDev_CH347::Novo_IIC_ScanDevAddr(UCHAR* pDevAddrs)
{
    if (!ifDevOpen)
        return ERR_IIC_NO_DEV;

    int devCount = 0;
    UCHAR tempDev[2] = { 0xFF,0xAA };
    for (UCHAR ix = 1; ix < NOVO_IIC_DEV_ADDR_MAX; ix++)
    {
        tempDev[0] = (ix << 1) + 1; //Start to Read
        if (CH347StreamI2C(mDevID, 2, &tempDev, 0, NULL))
        {
            *pDevAddrs++ = ix;
            devCount++;
        }
    }
    
    return devCount;
}

int NovoDev_CH347::Novo_IIC_RW_U8_Basic(UCHAR devAddr, UCHAR* pWriteData, \
    int writeLen, UCHAR* pReadData, int readLen)
{
    if (!ifDevOpen)
        return ERR_IIC_NO_DEV;

    if (CH347StreamI2C(mDevID, writeLen, pWriteData, readLen, pReadData))
        return SUCCESS;
    else
        return ERR_Failed;
}

int NovoDev_CH347::Novo_IIC_Wr_U8(UCHAR devAddr, UCHAR regAddr, UCHAR regData)
{
    if (!ifDevOpen)
        return ERR_IIC_NO_DEV;

    UCHAR writeBuffer[3] = {0};
    writeBuffer[0] = devAddr;
    writeBuffer[1] = regAddr;
    writeBuffer[2] = regData;

    return (Novo_IIC_RW_U8_Basic(devAddr, writeBuffer, sizeof(writeBuffer), NULL, 0));       
}

int NovoDev_CH347::Novo_IIC_Wr_U16(UCHAR devAddr, USHORT regAddr, USHORT regData)
{
    if (!ifDevOpen)
        return ERR_IIC_NO_DEV;

    UCHAR writeBuffer[5] = { 0 };
    writeBuffer[0] = devAddr;
    writeBuffer[1] = (UCHAR)(regAddr >> 8);
    writeBuffer[2] = (UCHAR)(regAddr);
    writeBuffer[3] = (UCHAR)(regData >> 8);
    writeBuffer[4] = (UCHAR)(regData);

    return (Novo_IIC_RW_U8_Basic(devAddr, writeBuffer, sizeof(writeBuffer), NULL, 0));
}

int NovoDev_CH347::Novo_IIC_Wr_U32(UCHAR devAddr, UINT regAddr, UINT regData)
{
    if (!ifDevOpen)
        return ERR_IIC_NO_DEV;

    UCHAR writeBuffer[9] = { 0 };
    writeBuffer[0] = devAddr;
    writeBuffer[1] = (UCHAR)(regAddr >> 24);
    writeBuffer[2] = (UCHAR)(regAddr >> 16);
    writeBuffer[3] = (UCHAR)(regAddr >> 8);
    writeBuffer[4] = (UCHAR)(regAddr);
    writeBuffer[5] = (UCHAR)(regData >> 24);
    writeBuffer[6] = (UCHAR)(regData >> 16);
    writeBuffer[7] = (UCHAR)(regData >> 8);
    writeBuffer[8] = (UCHAR)(regData);

    return (Novo_IIC_RW_U8_Basic(devAddr, writeBuffer, sizeof(writeBuffer), NULL, 0));
}

int NovoDev_CH347::Novo_IIC_Wr_U16U8(UCHAR devAddr, USHORT regAddr, UCHAR regData)
{
    if (!ifDevOpen)
        return ERR_IIC_NO_DEV;

    UCHAR writeBuffer[4] = { 0 };
    writeBuffer[0] = devAddr;
    writeBuffer[1] = (UCHAR)(regAddr >> 8);
    writeBuffer[2] = (UCHAR)(regAddr);
    writeBuffer[3] = (UCHAR)(regData);

    return (Novo_IIC_RW_U8_Basic(devAddr, writeBuffer, sizeof(writeBuffer), NULL, 0));
}

int NovoDev_CH347::Novo_IIC_Wr_U16U32(UCHAR devAddr, USHORT regAddr, UINT regData)
{
    if (!ifDevOpen)
        return ERR_IIC_NO_DEV;

    UCHAR writeBuffer[7] = { 0 };
    writeBuffer[0] = devAddr;
    writeBuffer[1] = (UCHAR)(regAddr >> 8);
    writeBuffer[2] = (UCHAR)(regAddr);
    writeBuffer[3] = (UCHAR)(regData >> 24);
    writeBuffer[4] = (UCHAR)(regData >> 16);
    writeBuffer[5] = (UCHAR)(regData >> 8);
    writeBuffer[6] = (UCHAR)(regData);

    return (Novo_IIC_RW_U8_Basic(devAddr, writeBuffer, sizeof(writeBuffer), NULL, 0));
}

int NovoDev_CH347::Novo_IIC_Rd_U8(UCHAR devAddr, UCHAR regAddr, UCHAR* pRegData)
{
    if (!ifDevOpen)
        return ERR_IIC_NO_DEV;

    UCHAR writeBuffer[2] = { 0 };
    writeBuffer[0] = devAddr;
    writeBuffer[1] = regAddr;

    return (Novo_IIC_RW_U8_Basic(devAddr, writeBuffer, sizeof(writeBuffer), pRegData, 1));
}

int NovoDev_CH347::Novo_IIC_Rd_U16(UCHAR devAddr, USHORT regAddr, USHORT* pRegData)
{
    int ret = ERR_Failed;
    if (!ifDevOpen)
        return ERR_IIC_NO_DEV;

    UCHAR writeBuffer[3] = { 0 };
    writeBuffer[0] = devAddr;
    writeBuffer[1] = (UCHAR)(regAddr >> 8);
    writeBuffer[2] = (UCHAR)(regAddr);

    ret = Novo_IIC_RW_U8_Basic(devAddr, writeBuffer, sizeof(writeBuffer), (UCHAR*)pRegData, 2);
    // LSB to MSB 
    LE2BE((UCHAR*)pRegData, 2);

    return ret;
}

int NovoDev_CH347::Novo_IIC_Rd_U32(UCHAR devAddr, UINT regAddr, UINT* pRegData)
{
    int ret = ERR_Failed;
    if (!ifDevOpen)
        return ERR_IIC_NO_DEV;

    UCHAR writeBuffer[5] = { 0 };
    writeBuffer[0] = devAddr;
    writeBuffer[1] = (UCHAR)(regAddr >> 24);
    writeBuffer[2] = (UCHAR)(regAddr >> 16);
    writeBuffer[3] = (UCHAR)(regAddr >> 8);
    writeBuffer[4] = (UCHAR)(regAddr);

    ret = Novo_IIC_RW_U8_Basic(devAddr, writeBuffer, sizeof(writeBuffer), (UCHAR*)pRegData, 4);
    // LSB to MSB 
    LE2BE((UCHAR*)pRegData, 4);

    return ret;
}

int NovoDev_CH347::Novo_IIC_Rd_U16U8(UCHAR devAddr, USHORT regAddr, UCHAR* pRegData)
{
    if (!ifDevOpen)
        return ERR_IIC_NO_DEV;

    UCHAR writeBuffer[3] = { 0 };
    writeBuffer[0] = devAddr;
    writeBuffer[1] = (UCHAR)(regAddr >> 8);
    writeBuffer[2] = (UCHAR)(regAddr);

    return (Novo_IIC_RW_U8_Basic(devAddr, writeBuffer, sizeof(writeBuffer), pRegData, 1));
}

int NovoDev_CH347::Novo_IIC_Rd_U16U32(UCHAR devAddr, USHORT regAddr, UINT* pRegData)
{
    int ret = ERR_Failed;
    if (!ifDevOpen)
        return ERR_IIC_NO_DEV;

    UCHAR writeBuffer[3] = { 0 };
    writeBuffer[0] = devAddr;
    writeBuffer[1] = (UCHAR)(regAddr >> 8);
    writeBuffer[2] = (UCHAR)(regAddr);

    ret = Novo_IIC_RW_U8_Basic(devAddr, writeBuffer, sizeof(writeBuffer), (UCHAR*)pRegData, 4);
    // LSB to MSB 
    LE2BE((UCHAR*)pRegData, 4);

    return ret;
}

///GPIO
int NovoDev_CH347::Novo_GPIO_Get(UCHAR mask, UCHAR* pData)
{
    if (!ifDevOpen)
        return ERR_IIC_NO_DEV;

    UCHAR rdDir;
    UCHAR rdData;
    if (!CH347GPIO_Get(mDevID, &rdDir, &rdData))
        return ERR_Failed;
        
    if (!CH347GPIO_Set(mDevID, mask, (rdDir & ~mask), rdData))
        return ERR_Failed;

    if (!CH347GPIO_Get(mDevID, &rdDir, &rdData))
        return ERR_Failed;

    *pData = mask & rdData;
    return SUCCESS;
}

int NovoDev_CH347::Novo_GPIO_Set(UCHAR mask, UCHAR data)
{
    if (!ifDevOpen)
        return ERR_IIC_NO_DEV;

    UCHAR rdDir;
    UCHAR rdData;
    if (!CH347GPIO_Get(mDevID, &rdDir, &rdData))
        return ERR_Failed;

    if (!CH347GPIO_Set(mDevID, mask, (rdDir | mask), data))
        return ERR_Failed;

    return SUCCESS;
}




